// Memory management
/*
 * mxmem.h
 * mx Memory management
 *
 */
//#include "config_fw.h"
#include "string.h"
//#include "includes_fw.h"
#include "lib_retina.h"
#include "mxmem.h"

//#if (CUSTOMER == PNS) && ((MODEL == 1) || (SUPPORT_UAC))

typedef	unsigned long	ulong;

#define	MX_OK			0
#define	MX_ERR01		1
#define	MX_ERR02		2
#define	MX_ERR03		3

#define MX_HEADER		((ulong)sizeof(ulong))
#define MX_SIZE(p)		(*(ulong*)p)
#define MX_NEXT(p)		(*((ulong*)p + 1))
#define MX_CELLEND(p)	(p + MX_HEADER + MX_SIZE(p))

void		*mxfreeptr = 0;
void		*mxroot;
ulong	mxsize;
char		mxerr;
extern int printk(const char *format, ...);
//#define	DEBUG_MSG	dbg_printf3
#define	DEBUG_MSG
/*
 * mxinit
 * Initialize memory pool and size
 */
void* mxinit(void *pool, unsigned long poolsize)
{
	mxroot = mxfreeptr = pool;
	mxsize = poolsize - MX_HEADER;
//	memset((char*)mxfreeptr + MX_HEADER, 0x55, mxsize);
	MX_SIZE(mxfreeptr) = mxsize;
	MX_NEXT(mxfreeptr) = 0;
	mxerr = MX_OK;
	dbg_printf(0, "MXINIT- MX memory start %x size %x\r\n", mxroot, mxsize);
	return mxfreeptr;
}

/*
 * mxalloc0
 * Alloc memory and fill 0
 */

void* mxalloc0(unsigned long memsize)
{
	void*	ptr;
	

	ptr = mxalloc(memsize);

	mxmemset(ptr, 0, memsize);
	return ptr;
}

/*
 * mxalloc
 * Alloc memory
 */
//unsigned long totalm = 0;
void* mxalloc(unsigned long memsize)

{
	char	*ptr, *tmp, *pre;

	if (memsize == 0)
		return NULL;
	//totalm+=memsize;
	//KK_Debug4i("",memsize,totalm);
	memsize = ((memsize + 3) >> 2) << 2;
	mxerr = MX_OK;
	ptr = (char*)mxfreeptr;
	if (!ptr)
		return NULL;
	pre = NULL;

	do {
		if (MX_SIZE(ptr) > (memsize + 2 * MX_HEADER)) {
			tmp = ptr;
			ptr += memsize + MX_HEADER;
			if (pre) {
				MX_NEXT(pre) = (ulong)ptr;
			} else {
				mxfreeptr = ptr;
			}
			MX_SIZE(ptr) = MX_SIZE(tmp) - (memsize + MX_HEADER);
			MX_NEXT(ptr) = MX_NEXT(tmp);
			MX_SIZE(tmp) = memsize;
			if (MX_SIZE(tmp) != memsize)
				dbg_printf(0, "@@@@ Alloc %x/%x %x@@@@\r\n", (tmp + MX_HEADER), memsize, tmp + MX_HEADER);

			return tmp + MX_HEADER;
		} else if (MX_SIZE(ptr) >= (memsize + MX_HEADER)) {
			if (pre)
				MX_NEXT(pre) = MX_NEXT(ptr);
			else
				mxfreeptr = (void*)MX_NEXT(ptr);
			// DEBUG_MSG("@@@@ Alloc %x %x @@@@", (ptr + MX_HEADER), memsize);
 
			return ptr + MX_HEADER;
		}
		pre = ptr;
		ptr = (char*)MX_NEXT(ptr);
	} while (ptr);
	
	debug_printf(0, "Memory NG!!!");
	return NULL;
}

void *mxmemcpy(void* dst, void* src, unsigned long size)
{
	//return memcpy((char*)dst+MX_HEADER, (char*)src+MX_HEADER, size);
	 memcpy((char*)dst, (char*)src, size);
	//int i;
	//for(i = 0; i< size;i++)
	 //*((char*)dst+i) = *((char*)src+i);	
    return dst;
}

void *mxmemmove(void* dst, void* src, unsigned long size)
{
	char* temp = (char*)mxalloc(size);
	mxmemcpy(temp, src, size);
	mxmemcpy(dst, temp, size);
	mxfree(temp);
	
	return dst;
}

void *mxmemset(void* dst, int val,unsigned long size )
{
	memset( dst, val,size);
	//int i;
	//char* p = (char*)dst;
	//for(i = 0; i< size;i++)
	// *(p+i) = val;
	
	return dst;	
}

void* mxcalloc(int len, unsigned long memsize)
{
	void*	ptr;
	
	ptr = mxalloc(memsize*len);
	mxmemset(ptr, 0, memsize*len);
	return ptr;
}

void* mxmemchr(const void* s, unsigned char c, unsigned long n)
{
    if (n != 0) {
    	const unsigned char *p = s;

    	do {
    		if (*p++ == c)
    			return ((void *)(p - 1));
    	} while (--n != 0);
    }
    return (NULL);
}

/*
 * mxrealloc
 * Realloc memory
 */

void* mxrealloc(void *memptr, unsigned long resize)

{
	char	*newptr;
	ulong	orgsize;
	
	
	resize = ((resize + 3) >> 2 ) << 2;
	mxerr = MX_OK;

	newptr = (char*)mxalloc(resize);

	if (newptr) {
		if (memptr) {
			orgsize = *(ulong*)((char*)memptr - MX_HEADER);
			memcpy(newptr, memptr, (resize > orgsize)? orgsize : resize);
			MXFREE(memptr);
		}
		return newptr;
	}
	return NULL;
}

/*
 * mxfree
 * Free memory
 */

void mxfree(void *memptr)

{
	char	*ptr, *the, *pre;
	
//	 DEBUG_MSG("@@@@ Free %x @@@@\r\n", memptr);
	if (!memptr) {

		return;
	}
	mxerr = MX_OK;
	ptr = (char*)memptr - MX_HEADER;

	if ((ulong)ptr < (ulong)mxroot) {

		mxerror(4, ptr);

		return;
	}
	if (MX_SIZE(ptr)    == 0      ||
		MX_SIZE(ptr)    >  mxsize ||
		MX_CELLEND(ptr) >  ((char*)mxroot + mxsize + MX_HEADER)) {

		mxerror(5, ptr);

		return;
	}
	//memset(memptr, 0xcc, MX_SIZE(ptr));
	the = mxfreeptr;
	pre = NULL;
	do {
		if (ptr >= the && ptr < (the + MX_HEADER + MX_SIZE(the))) {

			mxerror(6, ptr);

			return;
		}
		if (ptr < the) {
			if (MX_CELLEND(ptr) == the) {
				MX_SIZE(ptr) += MX_SIZE(the) + MX_HEADER;
				MX_NEXT(ptr)  = MX_NEXT(the);
			} else  if (MX_CELLEND(ptr) < the) {
				MX_NEXT(ptr) = (ulong)the;
			} else {

				mxerror(2, ptr);
				return;
			}
			if (pre  == NULL) {
				mxfreeptr = (void*)ptr;
				return;
			} else {
				MX_NEXT(pre) = (ulong)ptr;
				if (MX_CELLEND(pre) == (char*)MX_NEXT(pre)) {
					MX_SIZE(pre) += MX_SIZE(ptr) + MX_HEADER;
					MX_NEXT(pre)  = MX_NEXT(ptr);
				}
				return;
			}
		}
		pre = the;
	} while ((the = (char*)MX_NEXT(the)) != NULL);
	the = pre;
	if (ptr == MX_CELLEND(the)) {
		MX_SIZE(the) += MX_SIZE(ptr) + MX_HEADER;
	} else {
		MX_NEXT(ptr) = MX_NEXT(the);
		MX_NEXT(the) = (ulong)ptr;
	}
}

/*
 * for DEBUG use
 */
void mxlayout()
{
	char	*ptr;
	int		i;
	
	ptr = (char*)mxfreeptr;
	i = 0;
	while (ptr) {
//		DEBUG_MSG("No.%03d Free Address, size: %x, %x %x",
//					i, ptr, MX_SIZE(ptr), MX_NEXT(ptr));
		if (!(char*)MX_NEXT(ptr))
			break;
		i++;
		ptr = (char*)MX_NEXT(ptr);
	}
	dbg_printf(0, "No.%03d Free Address, size: %x, %x %x",
				i, ptr, MX_SIZE(ptr), MX_NEXT(ptr));
}


void mxerror(char errcode, void *ptr)

{

	dbg_printf(0, "MX Error %d %x %d\r\n", errcode, (unsigned long)ptr, MX_SIZE(ptr));

	mxerr = errcode;
}

//#endif